﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace M3G {
    public class Background : Object3D {

        #region Field
        uint  color;
        uint  colorClearMask;
        float depth;
        bool  depthClearEnabled;
        int   stencil;
        uint  stencilClearMask;
        #endregion

        #region Method
        public Background () {
            this.color = 0x00000000u;
            this.colorClearMask = 0xffffffffu;
            this.depth = 1.0f;
            this.depthClearEnabled = true;
            this.stencil = 0;
            this.stencilClearMask = 0xffffffffu;
        }

        protected Background (Background background)
            : base (background) {
            this.color = background.color;
            this.colorClearMask = background.colorClearMask;
            this.depth = background.depth;
            this.depthClearEnabled = background.depthClearEnabled;
            this.stencil = background.stencil;
            this.stencilClearMask = background.stencilClearMask;
        }
 

        public uint Color {
            get { return color; }
        }

        public void SetColor (uint ARGB) {
            this.color = ARGB;
        }

        public uint ColorClearMask {
            get { return colorClearMask; }
        }

        public void SetColorClearMask (uint mask) {
            var a = (mask & 0xff000000) >> 24;
            var r = (mask & 0x00ff0000) >> 16;
            var g = (mask & 0x0000ff00) >> 8;
            var b = (mask & 0x000000ff) >> 0;
            if (!(a == 0x00 || a == 0xff) || !(r == 0x00 || r == 0xff) || !(g == 0x00 || g == 0xff) || !(b == 0x00 || b == 0xff)) {
                throw new ArgumentException ("All mask components must be 0 or 0xff, mask=" + mask);
            }

            this.colorClearMask = mask;
        }

        public float Depth {
            get { return depth; }
        }

        public void SetDepth (float depth) {
            depth = Math.Max (0f, Math.Min (1f, depth));
        }

        public bool DepthClearEnabled {
            get { return depthClearEnabled; }
        }

        public void SetDepthClearEnable (bool enable) {
            depthClearEnabled = enable;
        }

        public int Stencil {
            get { return stencil; }
        }

        public void SetStencil (int stencil) {
            this.stencil = stencil;
        }

        public uint StencilClearMask {
            get { return stencilClearMask; }
        }

        public void SetStencilClearMask (uint mask) {
            this.stencilClearMask = mask;
        }

        public override int Animate (int time) {

            base.Animate (time);

            var animatedAlpha   = new float[1];
            var animatedColor   = new float[3];
            var animatedDepth   = new float[1];
            var animatedStencil = new float[1];
            var value           = new float[3];
            var animated        = new Dictionary<int, bool> (4);

            for (var i=0; i < AnimationTrackCount; i++) {
                var track = AnimationTrack[i];
                var ch    = AnimationTrackChannel[i];
                if (track.Controller == null || !track.Controller.Active (time)) {
                    continue;
                }
                var property = track.TargetProperty;
                var weight   = track.Controller.Weight;

                animated[property] = true;
                switch (property) {
                    case M3G.AnimationTrack.Alpha: {
                        track.Sample (time, ch, value);
                        animatedAlpha[0] = value[0] * weight;
                        break;
                    }
                    case M3G.AnimationTrack.Color: {
                        track.Sample (time, ch, value);
                        animatedColor[0] = value[0] * weight;
                        animatedColor[1] = value[1] * weight;
                        animatedColor[2] = value[2] * weight;
                        break;
                    }
                    case M3G.AnimationTrack.Depth: {
                        track.Sample (time, ch, value);
                        animatedDepth[0] = value[0] * weight;
                        break;
                    }
                    case M3G.AnimationTrack.Stencil: {
                        track.Sample (time, ch, value);
                        animatedStencil[0] = value[0] * weight;
                        break;
                    }
                }// switch
            }  // for

            if (animated[M3G.AnimationTrack.Alpha]) {
                var a = (uint)animatedAlpha[0].Clamp (0, 1) * 255;
                this.color = (color & 0x00ffffff) | (a << 24);
            }
            if (animated[M3G.AnimationTrack.Color]) {
                var r = (uint)animatedColor[0].Clamp (0, 1) * 255;
                var g = (uint)animatedColor[1].Clamp (0, 1) * 255;
                var b = (uint)animatedColor[2].Clamp (0, 1) * 255;
                this.color = (color & 0xff000000) | (r << 16) | (g << 8) | (b << 0);
            }
            if (animated[M3G.AnimationTrack.Depth]) {
                this.depth = (int)animatedDepth[0];
            }
            if (animated[M3G.AnimationTrack.Stencil]) {
                this.stencil = (int)animatedStencil[0];
            }

            return 0;
        }

        public override Object3D Duplicate () {
            return new Background (this);
        }

        #endregion

    }
}
